\chapter{GNU Regex库正则编程样例}
GNU Regex库有GNU、POSIX和BSD三种不同的用户界面，在此，分别就这三种用户界面给出
其最小工作示例。

\section{GNU 用户界面}

为使用GNU用户界面，需要在用\cinline{#include <regex.h>}引入GNU Regex库之前，用
\cinline{#define _GNU_SOURCE}定义\cinline{_GNU_SOURCE}宏，以启用相关类型定义、
函数声明、宏定义等内容（条件编译）。

\subsection{单字符串搜索}

在单一一个字符串中进行搜索是通过\cinline{re_search()}函数实现的，其最小工作
示例如代码\ref{code-search}所示。

\cvfile[label=code-search]{单字符串搜索}{gnu-regex/codes/gnu-interface/gnu-regex-search.c}

\begin{note}
  \begin{enumerate}
    \item 若不需要记录正则表达式分组搜索结果，则可以在第55---56行的%
        \cinline{re_search()}函数调用中，将\cinline{&regs}替换为\cinline{NULL}指针。
    \item 需要使用\cinline{regfree()}函数释放编译后的正则缓存所占用内存(第77行)。
    \item 如果使用了匹配寄存器，则需用\cinline{free()}函数释放其 \cinline{start} %
        和 \cinline{end} 成员指向的动态内存(第79---80行)。
  \end{enumerate}
\end{note}

\subsection{双字符串搜索}

两个字符串中进行搜索是通过\cinline{re_search_2()}函数实现的，其最小工作
示例如代码\ref{code-search2}所示。

\cvfile[label=code-search2]{双字符串搜索}{gnu-regex/codes/gnu-interface/gnu-regex-search-2.c}

\begin{note}
  \begin{enumerate}
    \item 在两个字符串进行搜索本质上是将两个字符串合并后进行搜索。
    \item 搜索结果中的位置索引是两个字符串合并后的位置索引。
  \end{enumerate}
\end{note}

\subsection{单字符串匹配}

在单独一个字符串中进行匹配是通过\cinline{re_match()}函数实现的，其最小工作
示例如代码\ref{code-match}所示。

\cvfile[label=code-match]{单字符串匹配}{gnu-regex/codes/gnu-interface/gnu-regex-match.c}

\subsection{双字符串匹配}

在两个字符串中进行匹配是通过\cinline{re_match_2()}函数实现的，其最小工作
示例如代码\ref{code-match2}所示。

\cvfile[label=code-match2]{双字符串匹配}{gnu-regex/codes/gnu-interface/gnu-regex-match-2.c}

\subsection{匹配寄存器}

正则表达式中的一个分组（小括号分组）可以匹配整个正则表达式所匹配字符串的一个
子符串。在匹配时，可以记录每个分组所匹配子字符串的开始(包含)和结束(不包含)位置。
GNU Regex库定义了一个匹配寄存器数组结构记录正则表达式中各分组的匹配信息，
使用匹配寄存器的最小工作示例如代码\ref{code-register}所示。

\cvfile[label=code-register]{双字符串匹配}{gnu-regex/codes/gnu-interface/gnu-regex-registers.c}

\begin{note}
  整个正则表达式是默认分组，记为group 0，其匹配信息记录于匹配寄存器的start和
  end成员指向的数组的0号元素中。
\end{note}

\subsection{重复搜索}

如果需要重复搜索所有的匹配，则可以使用匹配寄存器的默认分组(group 0)记录的位置
调整被搜索字符串的偏移实现，其最小工作示例如代码\ref{code-gnu-loop}所示。

\cvfile[label=code-gnu-loop]{GNU用户接口的重复搜索}%
  {gnu-regex/codes/gnu-interface/gnu-regex-loop.c}

\section{POSIX 用户界面}

使用POSIX用户界面时，则无需定义\cinline{#define _GNU_SOURCE}宏。

\subsection{静态内存管理}

在使用POSIX用户界面时，可以静态管理错误信息、匹配寄存器等数据，其
最小工作示例如代码\ref{code-posix}所示。

\cvfile[label=code-posix]{POSIX的静态内存管理}%
  {gnu-regex/codes/posix-interface/gnu-regex-posix.c}

\begin{note}
  \begin{enumerate}
    \item 若不需要记录正则表达式分组搜索结果，则可以在第42行的%
        \cinline{regexec()}函数调用中，将\cinline{nmatch}替换为\cinline{0}，
        将\cinline{pmatch}替换为\cinline{NULL}指针。
    \item 需要使用\cinline{regfree()}函数释放编译后的正则缓存所占用的内存(第69行)。
  \end{enumerate}
\end{note}

\subsection{动态内存管理}

在使用POSIX用户接口时，也可以动态管理错误信息、匹配寄存器等数据，其正则搜索的
最小工作示例如代码\ref{code-posix-dynamic}所示。

\cvfile[label=code-posix-dynamic]{POSIX的动态内存管理}%
  {gnu-regex/codes/posix-interface/gnu-regex-posix-dynamic.c}

\begin{note}
  \begin{enumerate}
    \item 可以先通过\cinline{regerror()}函数返回错误信息长度(第29行)，再利用该
        长度申请内存空间(第30---48行)。
    \item 可以通过编译后的正则缓存的\cinline{re_nsub}成员得到分组个数，在此需要
        为默认分组预留空间(第52行)。
  \end{enumerate}
\end{note}

\subsection{匹配寄存器}

在匹配后，便可以使用匹配寄存器定位提取需要的字符串，其最小工作示例如代码%
\ref{code-posix-grab}所示。

\cvfile[label=code-posix-grab]{POSIX的动态内存管理}%
  {gnu-regex/codes/posix-interface/gnu-regex-posix-match-once.c}

\begin{note}
  \begin{enumerate}
    \item 该最小工作示例未进行编译失败等处理。
    \item 匹配数组数组的\cinline{pmatch[0]}元素记录的是默认分组(group 0)匹配结果。
  \end{enumerate}
\end{note}

\subsection{重复搜索}

如果需要重复搜索所有匹配，则可以使用匹配寄存器中的默认分组(group 0)，通过在
被搜索字符串中进行偏移实现，其最小工作示例如代码\ref{code-posix-loop}所示。

\cvfile[label=code-posix-loop]{POSIX用户接口的重复搜索}
  {gnu-regex/codes/posix-interface/gnu-regex-posix-loop.c}

\section{BSD 用户界面}

在使用BSD用户界面时，需要在用\cinline{#include <regex.h>}引入GNU Regex库之前，用
\cinline{#define _GNU_SOURCE}和\cinline{#define _REGEX_RE_COMP}定义\cinline{_GNU_SOURCE}%
和\cinline{_REGEX_RE_COMP} 宏，以启用相关类型定义、函数声明与定义等内容（条件编译）。

使用BSD用户界面进行正则搜索的最小工作示例如代码\ref{code-bsd}所示。

\cvfile[label=code-bsd]{BSD正则搜索}{gnu-regex/codes/bsd-interface/gnu-regex-bsd.c}
